{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "768629e6",
   "metadata": {},
   "outputs": [],
   "source": [
    "# imports\n",
    "\n",
    "import os\n",
    "from dotenv import load_dotenv\n",
    "from openai import OpenAI\n",
    "\n",
    "from IPython.display import Markdown, display, update_display"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "84a945dc",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Load environment variables in a file called .env\n",
    "# Print the key prefixes to help with any debugging\n",
    "\n",
    "load_dotenv(override=True)\n",
    "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
    "google_api_key = os.getenv('GOOGLE_API_KEY')\n",
    "\n",
    "if openai_api_key:\n",
    "    print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
    "else:\n",
    "    print(\"OpenAI API Key not set\")\n",
    "\n",
    "if google_api_key:\n",
    "    print(f\"Google API Key exists and begins {google_api_key[:8]}\")\n",
    "else:\n",
    "    print(\"Google API Key not set\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ad8ae0b6",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Connect to OpenAI, Gemini\n",
    "openai = OpenAI()\n",
    "gemini_via_openai_client = OpenAI(\n",
    "    api_key=google_api_key, \n",
    "    base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\"\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f66cf12f",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Let's make a conversation between GPT-4.1-mini and Gemini-2.0-flash\n",
    "# We're using cheap versions of models so the costs will be minimal\n",
    "\n",
    "# game = \"Santorini\"\n",
    "no_questions = 3\n",
    "\n",
    "gpt_model = \"gpt-4o-mini\"\n",
    "gemini_model = \"gemini-2.0-flash\"\n",
    "\n",
    "gpt_system = \"You are a boardgame journalist. \\\n",
    "You tend to be objective and ask right questions to get to the core of the boardgame mechanics, \\\n",
    "visual appeal and time to setup the game. Your goal is to ask the right questions to get the best possible review of the board game.\" \\\n",
    "\"You ask one question at a time and wait for the other person to answer. \\\n",
    "You do not answer any own questions. You always try to build on the previous answer.\"\n",
    "\n",
    "gemini_system = \"You are a boardgame critique; \\\n",
    "you tend to objectively analyze everything when it comes to a board game gameplay, visual appeal and time to setup the game. \\\n",
    "Your goal is to provide constructive criticism so the board gaming community can benefit from these insights.\" \\\n",
    "\"You answer one question at a time and wait for the other person to ask the next question. \\\n",
    "You do not ask any questions you always just answer the previous question. \\\n",
    "If the other person is very positive, you try to point out flaws in the game. \\\n",
    "If the other person is very negative, you try to point out good aspects of the game.\"\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "33266f0c",
   "metadata": {},
   "outputs": [],
   "source": [
    "def call_boardgame_journalist(gpt_messages, gemini_messages):\n",
    "    messages = [{\"role\": \"system\", \"content\": gpt_system}]\n",
    "    for gpt, gemini in zip(gpt_messages, gemini_messages):\n",
    "        messages.append({\"role\": \"user\", \"content\": gpt})\n",
    "        messages.append({\"role\": \"assistant\", \"content\": gemini})\n",
    "    completion = openai.chat.completions.create(\n",
    "        model=gpt_model,\n",
    "        messages=messages\n",
    "    )\n",
    "    return completion.choices[0].message.content"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "53d42055",
   "metadata": {},
   "outputs": [],
   "source": [
    "def call_boardgame_critique(gpt_messages, gemini_messages):\n",
    "    messages = [{\"role\": \"system\", \"content\": gemini_system}]\n",
    "    for gpt, gemini in zip(gpt_messages, gemini_messages):\n",
    "        messages.append({\"role\": \"user\", \"content\": gpt})\n",
    "        messages.append({\"role\": \"assistant\", \"content\": gemini})\n",
    "    messages.append({\"role\": \"user\", \"content\": gpt_messages[-1]})\n",
    "    completion = gemini_via_openai_client.chat.completions.create(\n",
    "        model=gemini_model,\n",
    "        messages=messages\n",
    "    )\n",
    "    return completion.choices[0].message.content\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5aa66868",
   "metadata": {},
   "outputs": [],
   "source": [
    "def run_boardgame_conversation(boardgame_name):\n",
    "    gpt_messages = [f\"I would like to review the board game {boardgame_name}.\"]\n",
    "    gemini_messages = [f\"Sure, ask me anything about the board game {boardgame_name}.\"]\n",
    "\n",
    "    print(f\"Journalist:\\n{gpt_messages[0]}\\n\")\n",
    "    print(f\"Critique:\\n{gemini_messages[0]}\\n\")\n",
    "\n",
    "    for i in range(no_questions):\n",
    "        print(f\"\\n\\n***Question {i + 1}***\\n\\n\")\n",
    "        gpt_next = call_boardgame_journalist(gpt_messages, gemini_messages)\n",
    "        print(f\"Journalist:\\n{gpt_next}\\n\")\n",
    "        gpt_messages.append(gpt_next)\n",
    "\n",
    "        gemini_next = call_boardgame_critique(gpt_messages, gemini_messages)\n",
    "        print(f\"Critique:\\n{gemini_next}\\n\")\n",
    "        gemini_messages.append(gemini_next)\n",
    "\n",
    "    return \"\\n\".join(f\"*Journalist*: {g}\\n*Critique*: {c}\" for g, c in zip(gpt_messages, gemini_messages))\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "51c9dadc",
   "metadata": {},
   "outputs": [],
   "source": [
    "import gradio as gr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "548efb27",
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'gr' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mNameError\u001b[39m                                 Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[1]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m view = \u001b[43mgr\u001b[49m.Interface(\n\u001b[32m      2\u001b[39m     fn=run_boardgame_conversation,\n\u001b[32m      3\u001b[39m     inputs=[gr.Textbox(label=\u001b[33m\"\u001b[39m\u001b[33mInput the name of the board game:\u001b[39m\u001b[33m\"\u001b[39m)],\n\u001b[32m      4\u001b[39m     outputs=[gr.Markdown(label=\u001b[33m\"\u001b[39m\u001b[33mConversation:\u001b[39m\u001b[33m\"\u001b[39m)],\n\u001b[32m      5\u001b[39m     flagging_mode=\u001b[33m\"\u001b[39m\u001b[33mnever\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m      6\u001b[39m )\n\u001b[32m      7\u001b[39m view.launch()\n",
      "\u001b[31mNameError\u001b[39m: name 'gr' is not defined"
     ]
    }
   ],
   "source": [
    "# Create a Gradio interface for running boardgame conversations.\n",
    "# The interface takes the board game name as input and displays the conversation as Markdown.\n",
    "view = gr.Interface(\n",
    "    fn=run_boardgame_conversation,\n",
    "    inputs=[gr.Textbox(label=\"Input the name of the board game:\")],\n",
    "    outputs=[gr.Markdown(label=\"Conversation:\")],\n",
    "    flagging_mode=\"never\"\n",
    ")\n",
    "view.launch()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "venv (3.13.5)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
